﻿using System.Collections.Generic;
using OrderMicroService.Infrastructure.Repository.Common;
using OrderMicroService.Types.Types;

namespace OrderMicroService.Infrastructure.Repository.DAO
{
    public class DbContext<T, ID>
        where T : IAggregate<ID>
        where ID : IIdentifier
    {
        private readonly Dictionary<ID, T> aggregateMap;

        public DbContext()
        {
            aggregateMap = new Dictionary<ID, T>();
        }

        /// <summary>
        /// 附加
        /// </summary>
        /// <param name="aggregate"></param>
        public void Attach(T aggregate)
        {
            if (aggregate.GetId() != null)
            {
                if (!aggregateMap.ContainsKey(aggregate.GetId()))
                {
                    Merge(aggregate);
                }
            }
        }

        /// <summary>
        /// 分离
        /// </summary>
        /// <param name="aggregate"></param>
        public void Detach(T aggregate)
        {
            if (aggregate.GetId() != null)
            {
                aggregateMap.Remove(aggregate.GetId());
            }
        }

        public EntityDiff DetectChanges(T aggregate)
        {
            if (aggregate.GetId() == null)
            {
                return EntityDiff.EMPTY;
            }

            T snapshot = aggregateMap[aggregate.GetId()];
            if (snapshot == null)
            {
                Attach(aggregate);
            }
            return DiffUtils.Diff<T, ID>(snapshot, aggregate);
        }

        public T Find(ID id)
        {
            return aggregateMap[id];
        }

        public void Merge(T aggregate)
        {
            if (aggregate.GetId() != null)
            {
                T snapshot = SnapshotUtils.Snapshot<T, ID>(aggregate);
                aggregateMap.Add(aggregate.GetId(), snapshot);
            }
        }

        public void SetId(T aggregate, ID id)
        {
            ReflectionUtils.WriteField("id", aggregate, id);
        }
    }
}